#include <iostream>
#include <cerrno>
#include <cstring>
#include <string>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "log.hpp"

using namespace std;

enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
    USE_ERROR
};

void useTips(char *command)
{
    cout << "useTips:" << command << " ip" << " port" << endl;
}

int main(int argc, char *argv[])
{
    EnableFile();
    if (argc != 3)
    {
        useTips(argv[0]);
        LOG(ERROR, "client: parameter usage error!");
        exit(USE_ERROR);
    }
    LOG(ERROR, "parameter usage success!");

    // 1、定义一个交流终端
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        LOG(FATAL, "client: creates socket fatally, errno:%d, errmsg:%s", errno, strerror(errno));
        exit(USE_ERROR);
    }
    LOG(FATAL, "client: creates socket successfully");

    // 2、用户端要不要将sockfd和自己的socket信息绑定呢
    // 一定要，但不是和server一样显示使用bind绑定（不建议也不推荐），
    // 什么时候绑定呢，如何绑定？当第一次发送数据的时候，OS会自动的给自己随机绑定port
    // 为什么呢？避免客户端port冲突，因为当你给你的客户端绑定某个端口号之后，另外的客户端也绑定了这个端口号，此时你主机上这两个服务就会造成冲突，无法确定网络中的唯一进程

    // 3、构建目标主机的socket信息
    struct sockaddr_in destaddr;
    memset(&destaddr, 0, sizeof(destaddr));
    destaddr.sin_family = AF_INET;
    destaddr.sin_port = htons(atoi(argv[2]));
    destaddr.sin_addr.s_addr = inet_addr(argv[1]);

    while (true)
    {
        // 4、发送信息
        string msg = "";
        cout << "please enter:";
        getline(cin, msg);
        int ret = sendto(sockfd, msg.c_str(), msg.size(), 0, (struct sockaddr *)&destaddr, sizeof(destaddr));
        if (ret == -1)
        {
            LOG(ERROR, "client: sendto is fatal");
        }
        LOG(ERROR, "client: sendto is:%s", msg.c_str());

        // 5、接收来自server的回显
        char buf[1024];
        sockaddr_in srcaddr;
        socklen_t len = sizeof(srcaddr);
        ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&srcaddr, &len);
        if (ret > 0)
        {
            cout << "[" << inet_ntoa(srcaddr.sin_addr) << "]" << "[" << ntohs(srcaddr.sin_port) << "]" << "echo is:" << buf << endl;
            LOG(INFO, "client: %s:%d, echo is successful, mes:%s", inet_ntoa(srcaddr.sin_addr), ntohs(srcaddr.sin_port), buf);
        }
    }

    return 0;
}